import { Vector } from './vector';

const Rusha = require('rusha')

/**
 * val不超过max、min
 * @param {number} val 
 * @param {number} max 
 * @param {number} min 
 */
export function clamp(val, min, max){
  return Math.max(min, Math.min(val, max));
}

/**
 * 等待两帧时间
 * @returns 
 */
export function waitNextFrame(){
  return new Promise(resolve => {
    window.requestAnimationFrame(() => {
      window.requestAnimationFrame(() => {
        resolve();
      })
    })
  })
}

/**
 * 删除节点下所有子节点
 * @param {HTMLElement} elem 
 */
export function removeAllChildren(elem){
  if(elem){
    let range = document.createRange();
    range.selectNodeContents(elem);
    range.deleteContents();
  }
}

export function getRandomNum(){
  return crypto.getRandomValues(new Uint32Array(1)) / 0xffffffff;
}

// 获取一个随机字符串，这个数据不会是数组中的任何一项
export function randomNoArr(arr = [], prefix = ''){
  let num = (getRandomNum() + '').slice(2);

  while(arr.indexOf(prefix + num) > -1){
    num = (getRandomNum() + '').slice(2);
  }

  return prefix + num;
}

/**
 * 随机选择数组中其中一项
 * @param {Array} arr 
 */
export function randomChoice(arr){
  return arr[Math.floor(getRandomNum() * arr.length)];
}

/**
 * 随机选择数组中的n项，
 * @param {Array} arr 
 * @param {Number} n 
 * @param {Boolean} flag 值是否可重复
 * @returns 
 */
export function randomChoiceNum(arr, n, flag = false){
  if(arr.length <= 0 || n <= 0) return [];
  let index = ~~(getRandomNum() * arr.length);
  let result = null;
  if(flag){
    result = [arr[index]];
  } else {
    result = arr.splice(index, 1);
  }

  return result.concat(randomChoiceNum(arr, --n, flag));
}

/**
 * 按照随机比例返回，如果随机成功，将会返回
 * @param {*} arr 
 * @returns 
 */
export function randomArrProportion(arr){
  let result = [];
  for(let i = 0; i < arr.length; i++){
    let random = getRandomNum() * 100;
    const item = arr[i];
    
    if(random <= item.random) result.push(item.data);
  }

  return result;
}

export function cachebust(path){
  
  return path;
}

export function sha1(str){
  return Rusha.createHash().update(str).digest('hex');
}

/**
 * 删除给定索引的值
 * @param {Array<any>} array
 * @param {number} index
 */
export function arrayDelete(array, index) {
  if (index < 0 || index >= array.length) {
    throw new Error("Out of bounds");
  }
  array.splice(index, 1);
}

/**
 * 在数组中删除指定值
 * @param {Array<any>} array
 * @param {any} value
 */
export function arrayDeleteValue(array, value) {
  if (array == null) {
    throw new Error("Tried to delete from non array!");
  }
  const index = array.indexOf(value);
  if (index < 0) {
    console.error("Value", value, "not contained in array:", array, "!");
    return value;
  }
  return arrayDelete(array, index);
}

/**
 * 将时间戳改成'几天前'格式
 * @param {number} timestamp Seconds
 * @returns {string}
 */
export function formatSecondsToTimeAgo(timestamp) {
  // 补全为13位
  var arrTimestamp = (timestamp + '').split('');
  for (var start = 0; start < 13; start++) {
      if (!arrTimestamp[start]) {
          arrTimestamp[start] = '0';
      }
  }
  timestamp = arrTimestamp.join('') * 1;
  var minute = 1000 * 60;
  var hour = minute * 60;
  var day = hour * 24;
  var halfamonth = day * 15;
  var month = day * 30;
  var now = new Date().getTime();
  var diffValue = now - timestamp;

  // 如果本地时间反而小于变量时间
  if (diffValue < 0) {
      return '不久前';
  }
  // 计算差异时间的量级
  var monthC = diffValue / month;
  var weekC = diffValue / (7 * day);
  var dayC = diffValue / day;
  var hourC = diffValue / hour;
  var minC = diffValue / minute;

  // 数值补0方法
  var zero = function (value) {
      if (value < 10) {
          return '0' + value;
      }
      return value;
  };

  // 使用
  if (monthC > 4) {
      // 超过1年，直接显示年月日
      return (function () {
          var date = new Date(timestamp);
          return date.getFullYear() + '年' + zero(date.getMonth() + 1) + '月' + zero(date.getDate()) + '日';
      })();
  } else if (monthC >= 1) {
      return parseInt(monthC) + "月前";
  } else if (weekC >= 1) {
      return parseInt(weekC) + "周前";
  } else if (dayC >= 1) {
      return parseInt(dayC) + "天前";
  } else if (hourC >= 1) {
      return parseInt(hourC) + "小时前";
  } else if (minC >= 1) {
      return parseInt(minC) + "分钟前";
  }
  return '刚刚';
}

/**
 * 创建一个div容器
 * @param {*} id 
 * @param {*} classes 
 * @param {*} innerHTML 
 * @returns 
 */
function makeDivElement(id = null, classes = [], innerHTML = ''){
  const div = document.createElement('div')
  if(id){
    div.id = id;
  }

  for(let i = 0; i < classes.length; i++){
    if(classes[i]){
      div.classList.add(classes[i])
    }
  }

  div.innerHTML = innerHTML;
  return div;
}

/**
 * 创建一个div容器并置入父级元素中
 * @param {Element} parent 父级
 * @param {String} id 
 * @param {Array} classes 
 * @param {String} innerHTML 内容
 * @returns 
 */
export function makeDiv(parent, id = null, classes = [], innerHTML = '', insertBefore = false){
  const div = makeDivElement(id, classes, innerHTML);
  if(insertBefore){
    parent.insertBefore(div, insertBefore)
  } else {
    parent.appendChild(div)
  }
  return div;
}

/**
 * 深拷贝对象
 * @param {Object} obj 
 * @returns 
 */
export function copyObj(obj){
  return JSON.parse(JSON.stringify(obj))
}

/**
 * 比较两个对象都拥有的key，如果值不同将会返回
 * @param {Object} obj 
 * @param {Object} obj2 
 * @returns 
 */
export function diffObject(obj, obj2){
  let result = {};

  for(let i in obj){
    if(!obj2[i]) continue;
    if(obj[i] !== obj2[i]){
      result[i] = obj2[i]
    }
  }

  return result;
}

/**
 * 保存数字几位小数
 * @param {Number} num 
 * @param {Number} n
 */
export function keepDecimal(num, n){
  let n10Multiple = Math.pow(10, n);
  return ~~(num * n10Multiple) / n10Multiple;
}

/**
 * 给对象中的每个值执行函数，并返回一个新的对象
 * @param {Object} obj 
 * @param {Function} cb 
 */
export function ObjectMapCb(obj, cb){
  let result = {};
  Object.keys(obj).map(key => {
    let value = obj[key]
    result[key] = cb(value);
  })
  return result;
}

export function createID(){
  let id = 1;
  return function(){
    return id++;
  }
}

/**
 * 获取数据的类型
 * @param {*} data 
 * @returns 
 */
export function getObjectType(data){
  let type = Object.prototype.toString.call(data);

  type = type.split(' ');
  type = type[1].substr(0, type[1].length - 1);

  return type;
}

/**
 * 匹配数组中匹配的数据
 * @param {*} arr 
 * @param {*} matchObj 
 * @returns 
 */
export function matchArray(arr, matchObj, deep = false){
  for(let i = 0; i < arr.length; i++){
    let flag = true;
    let item = arr[i];

    if(deep) item = item[deep];

    Object.keys(matchObj).map(key => {
      if(matchObj[key] !== item[key]) flag = false;
    });

    if(flag) return arr[i];
  }

  return false;
}

/**
 * 
 * @param {HTMLElement} dom 
 */
export function handlerInputKeyup(dom, cb){
  dom.addEventListener('keyup', ev => {
    cb(dom.value);
  })
}

/**
 * 删除对象中值为数组并且没有任何项的数据
 * @param {*} obj 
 * @returns 
 */
export function ObjectDeleteValArray0(obj){
  Object.keys(obj).map(key => {
    let val = obj[key];
    let type = getObjectType(val);
    if(type == 'Array'){
      if(val.length < 1) delete obj[key];
    }
  })

  return obj;
}

/**
 * 在对象中找到list中存在的key进行随机获取其中一项，key的值需要为数组
 * @param {*} obj 
 * @param {*} list 
 * @returns 
 */
export function ObjectValArrOnly(obj, list){
  let type = getObjectType(obj);
  if(type !== 'Object') {
    return obj;
  }
  let result = {};

  Object.keys(obj).map(key => {
    if(list.indexOf(key) > -1){
      result[key] = randomChoice(obj[key]);
    } else if(type == 'Object'){
      result[key] = ObjectValArrOnly(obj[key], list);
    }
  })

  return result;
}

/**
 * 获取对象中需要的key
 */
export function ObjectNeedKey(obj, arr){
  let result = {}
  Object.keys(obj).map(key => {
    if(arr.indexOf(key) > -1){
      result[key] = obj[key]
    }
  })

  return result;
}

/**
 * 删除对象中不要的key
 * @param {*} obj 
 * @param {*} arr 
 */
export function ObjectDelKey(obj, arr){
  let result = {};
  Object.keys(obj).map(key => {
    if(arr.indexOf(key) <= -1){
      result[key] = obj[key]
    }
  })

  return result;
}

// 对比两个对象的值是否完全相等 返回值 true/false
export function isObjectValueEqual (a = {}, b = {}, arr = []) {   
  //取对象a和b的属性名
  let aProps = Object.keys(a);
  let bProps = Object.keys(b);

  aProps = aProps.filter(key => arr.indexOf(key) <= -1);
  bProps = bProps.filter(key => arr.indexOf(key) <= -1);

  //判断属性名的length是否一致
  if (aProps.length != bProps.length) {
    return false;
  }
  //循环取出属性名，再判断属性值是否一致
  for (let i = 0; i < aProps.length; i++) {
    let propName = aProps[i];
    let aType = getObjectType(a[propName]);
    let bType = getObjectType(b[propName]);
    if(['Object', 'Array'].indexOf(aType) > -1
    ){
      if( aType !== bType
        && JSON.stringify(a[propName]) != JSON.stringify(b[propName])){
        return false;
      }
    } 
    else if (a[propName] != b[propName]) {
      return false;
    }
  }
  return true;
}

export function ArrUnique(arr){
  return Array.from(new Set(arr))
}

/**
 * 动画删除元素，通过写css动画来将元素隐藏，然后在cb回调中对该元素进行处理
 */
export function animRemoveElement(element, cb, delay = 300, showTime = 0){
  setTimeout(() => {
    element.classList.add('remove-anim');
    setTimeout(() => {
      element.classList.remove('remove-anim')
      cb && cb();
    }, delay);
  }, showTime);
}

/**
 * 获取数值在数组中的数据
 * @returns 
 */
export function getValueInArray(array, value, getIndex = false){
  let data = array[0];

  for(let i = 0; i < array.length; i++){
    if(array[i].num <= value && (!array[i + 1] ||
      array[i + 1].num > value)
    ){
      if(getIndex){
        data = i;
      } else {
        data = array[i];
      }
    }
  }

  return data;
}

export function getArcPoint(dot1, dot2, angle) {
  var x1 = dot1[0];
  var y1 = dot1[1];
  var x2 = dot2[0];
  var y2 = dot2[1];
  var PI = Math.PI;

  // 两点间的x轴夹角弧度
  var xAngle=Math.atan2((y2-y1), (x2-x1));
  // 转为角度
  xAngle = 360*xAngle/(2*PI);
  // 两点间的长度
  var L=Math.sqrt((y2-y1)*(y2-y1)+(x2-x1)*(x2-x1));
  // 计算等腰三角形斜边长度
  var L2 = L/2 / Math.cos(angle* 2*PI/360);

  // 求第一个顶点坐标，位于下边
  var val1=[];
  // 求第二个顶点坐标，位于上边
  var val2=[];
  val1[0]=x1+Math.round(L2 * Math.cos((xAngle+angle)* 2*PI/360));
  val1[1]=y1+Math.round(L2 * Math.sin((xAngle+angle)* 2*PI/360));
  val2[0]=x1+Math.round(L2 * Math.cos((xAngle-angle)* 2*PI/360));
  val2[1]=y1+Math.round(L2 * Math.sin((xAngle-angle)* 2*PI/360));

  return [val1, val2];
}

/**
 * 获取其参数，如果没有，则获取其他
 */
export function getAttrOrOther(obj, key, ...other){
  if(obj && obj[key]){
    return obj[key];
  }

  for(let i = 0; i < other.length; i++){
    if(other[i]) return other[i];
  }

  return null;
}

let slowOutTextTimer = null;

export function slowOutText(element, text){
  clearInterval(slowOutTextTimer);
  let i = 0;
  slowOutTextTimer = setInterval(() => {
    element.innerText = text.substring(0, i);
    i++;
    if(i > text.length){
      clearInterval(slowOutTextTimer);
    }
  }, 40);
}

// 将数字转换为M:S格式的时间
export function formatTimeMS(time){
  let m = Math.floor(time / 60);
  let s = time % 60;
  return `${m < 10 ? '0' + m : m}:${s < 10 ? '0' + s : s}`;
}